﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SceneEngine;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;
using System;

namespace SceneEditor
{
    public enum GizmoMode
    {
        Translate,
        Rotate,
        Scale,
    }

    public enum GizmoAxis
    {
        X,
        Y,
        Z,
        None
    }

    public enum GizmoOrientation
    {
        Local,
        World,
        Camera
    }

    public class Gizmo
    {
        private Model[] models = new Model[3];
        private Matrix[] modelLocalSpace = new Matrix[3];
        private Matrix[] bones;

        private Vector3 position;
        private float scale;

        private Vector3 initialPosition;
        private Vector3 initialScale;
        private Quaternion initialRotation;

        private bool visible;
        private GizmoOrientation orientation = GizmoOrientation.World;

        private Vector3 currentAxis;
        private GizmoAxis gizmoAxis = GizmoAxis.None;
        private bool manipulating;

        private GroupObject transforms;

        private float gridSpacing;
        private bool snapToGrid;

        private MouseState mouseState;
        private MouseState prevMouseState;

        private Vector2 mouseDifference = Vector2.Zero;
        private Vector3 positionFloat = Vector3.Zero;

        private Matrix Rotation
        {
            get 
            {
                if (orientation == GizmoOrientation.Local)
                {
                    BaseObject entity = EngineGlobals.Scene.GetBaseObject(transforms.Objects[0]);
                    return Matrix.CreateFromQuaternion(entity.Rotation);
                }
                else if (orientation == GizmoOrientation.Camera)
                {
                    return Matrix.CreateRotationY(EngineGlobals.Camera.Yaw);
                }

                return Matrix.Identity;
            }
        }
        private Matrix World
        {
            get
            {
                if (orientation == GizmoOrientation.Local || orientation == GizmoOrientation.Camera)
                    return Matrix.CreateScale(scale) * Rotation * Matrix.CreateTranslation(position);
                else if (orientation == GizmoOrientation.World)
                    return Matrix.CreateScale(scale) * Matrix.CreateTranslation(position);

                return Matrix.Identity;
            }
        }

        private GizmoMode gizmoMode;

        // -- Lines (Vertices) -- //
        private VertexPositionColor[] translationLineVertices;
        private float lineLength = 3f;
        private float lineOffset = 0.5f;

        private BasicEffect lineEffect;

        // -- Quads -- //
        Quad[] quads;
        BasicEffect quadEffect;

        // -- Colors -- //
        private Color[] axisColors;
        private Color highlightColor;

        // -- BoundingBoxes -- //
        #region BoundingBoxes

        private BoundingOrientedBox X_Box
        {
            get
            {
                Vector3 center = (translationLineVertices[1].Position + Vector3.UnitX / 2) / 2;
                Quaternion rotationQuat = Quaternion.CreateFromRotationMatrix(Rotation);

                return new BoundingOrientedBox(Vector3.Transform(center, World),
                    new Vector3(center.X * scale, 0.2f, 0.2f), rotationQuat);
            }
        }

        private BoundingOrientedBox Y_Box
        {
            get
            {
                Vector3 center = (translationLineVertices[7].Position + Vector3.UnitY / 2) / 2;
                Quaternion rotationQuat = Quaternion.CreateFromRotationMatrix(Rotation);

                return new BoundingOrientedBox(Vector3.Transform(center, World),
                    new Vector3(0.2f, center.Y * scale, 0.2f), rotationQuat);
            }
        }

        private BoundingOrientedBox Z_Box
        {
            get
            {
                Vector3 center = (translationLineVertices[13].Position + Vector3.UnitZ / 2) / 2;
                Quaternion rotationQuat = Quaternion.CreateFromRotationMatrix(Rotation);

                return new BoundingOrientedBox(Vector3.Transform(center, World),
                    new Vector3(0.2f, 0.2f, center.Z * scale), rotationQuat);
            }
        }

        //private BoundingOrientedBox XZ_Box
        //{
        //    get
        //    {
        //        return new BoundingOrientedBox(Vector3.Transform(new Vector3(lineOffset, 0, lineOffset), World),
        //            new Vector3(lineOffset, boxThickness, lineOffset), Quaternion.CreateFromRotationMatrix(Rotation));
        //    }
        //}

        //private BoundingOrientedBox XY_Box
        //{
        //    get
        //    {
        //        return new BoundingOrientedBox(Vector3.Transform(new Vector3(lineOffset, lineOffset, 0), World),
        //            new Vector3(lineOffset, lineOffset, boxThickness), Quaternion.CreateFromRotationMatrix(Rotation));
        //    }
        //}

        //private BoundingOrientedBox YZ_Box
        //{
        //    get
        //    {
        //        return new BoundingOrientedBox(Vector3.Transform(new Vector3(0, lineOffset, lineOffset), World),
        //            new Vector3(boxThickness, lineOffset, lineOffset), Quaternion.CreateFromRotationMatrix(Rotation));
        //    }
        //}

        #endregion

        // -- BoundingSpheres -- //
        #region BoundingSpheres
        private BoundingSphere X_Sphere
        {
            get
            {
                switch (gizmoMode)
                {
                    case GizmoMode.Translate:
                        {
                            return new BoundingSphere(Vector3.Transform(translationLineVertices[1].Position +
                                Vector3.UnitX / 2.0f, World), Math.Max(scale / 2.0f, 0.001f));
                        }
                    case GizmoMode.Rotate:
                        {
                            return new BoundingSphere(Vector3.Transform(translationLineVertices[1].Position, World), Math.Max(scale / 2.0f, 0.001f));
                        }
                    case GizmoMode.Scale:
                        {
                            return new BoundingSphere(Vector3.Transform(translationLineVertices[1].Position +
                                Vector3.UnitX / 2.0f, World), Math.Max(scale / 4.0f * 3.0f, 0.001f));
                        }
                }

                return new BoundingSphere();
            }
        }

        private BoundingSphere Y_Sphere
        {
            get
            {
                switch (gizmoMode)
                {
                    case GizmoMode.Translate:
                        {
                            return new BoundingSphere(Vector3.Transform(translationLineVertices[7].Position +
                                Vector3.UnitY / 2.0f, World), Math.Max(scale / 2.0f, 0.001f));
                        }
                    case GizmoMode.Rotate:
                        {
                            return new BoundingSphere(Vector3.Transform(translationLineVertices[7].Position, World), Math.Max(scale, 0.001f));
                        }
                    case GizmoMode.Scale:
                        {
                            return new BoundingSphere(Vector3.Transform(translationLineVertices[7].Position +
                                Vector3.UnitY / 2.0f, World), Math.Max(scale / 4.0f * 3.0f, 0.001f));
                        }
                }

                return new BoundingSphere();
            }
        }

        private BoundingSphere Z_Sphere
        {
            get 
            {
                switch (gizmoMode)
                {
                    case GizmoMode.Translate:
                    {
                        return new BoundingSphere(Vector3.Transform(translationLineVertices[13].Position +
                            Vector3.UnitZ / 2.0f, World), Math.Max(scale / 2.0f, 0.001f));
                    }
                    case GizmoMode.Rotate:
                    {
                        return new BoundingSphere(Vector3.Transform(translationLineVertices[13].Position, World), Math.Max(scale / 2, 0.001f)); 
                    }
                    case GizmoMode.Scale:
                    {
                        return new BoundingSphere(Vector3.Transform(translationLineVertices[13].Position +
                            Vector3.UnitZ / 2.0f, World), Math.Max(scale / 4.0f * 3.0f, 0.001f));
                    }
                }

                return new BoundingSphere();
            }
        }
        #endregion

        public Vector3 InitialPosition
        {
            get { return initialPosition; }
            set { initialPosition = value; }
        }
        public Vector3 InitialScale
        {
            get { return initialPosition; }
            set { initialPosition = value; }
        }
        public Quaternion InitialRotation
        {
            get { return initialRotation; }
            set { initialRotation = value; }
        }

        public bool Manipulating
        {
            get { return manipulating; }
        }
        public GizmoOrientation Oritentation
        {
            get { return orientation; }
            set { orientation = value; }
        }

        public float GridSpacing
        {
            get { return gridSpacing; }
            set { gridSpacing = value; }
        }
        public bool SnapToGrid
        {
            get { return snapToGrid; }
            set { snapToGrid = value; }
        }

        public GizmoMode GizmoMode
        {
            get { return gizmoMode; }
            set
            {
                gizmoMode = value;
            }
        }
        public virtual GroupObject Transforms
        {
            get { return transforms; }

            set
            {
                transforms = value;

                if (transforms != null)
                {
                    positionFloat = transforms.Position;
                    transforms.Changed += new ChangedEventHandler(TransformsChanged);
                }
            }
        }

        public Gizmo() 
        {
            models[0] = EditorGlobals.EditorContent.Load<Model>("Editor\\gizmo_translate");
            models[1] = EditorGlobals.EditorContent.Load<Model>("Editor\\gizmo_rotate");
            models[2] = EditorGlobals.EditorContent.Load<Model>("Editor\\gizmo_scale");

            modelLocalSpace[0] = Matrix.CreateWorld(new Vector3(lineLength, 0, 0), Vector3.Left, Vector3.Up);
            modelLocalSpace[1] = Matrix.CreateWorld(new Vector3(0, lineLength, 0), Vector3.Down, Vector3.Left);
            modelLocalSpace[2] = Matrix.CreateWorld(new Vector3(0, 0, lineLength), Vector3.Forward, Vector3.Up);

            lineEffect = new BasicEffect(EngineGlobals.GraphicsDevice);
            lineEffect.VertexColorEnabled = true;
            lineEffect.AmbientLightColor = Vector3.One;
            lineEffect.EmissiveColor = Vector3.One;

            quadEffect = new BasicEffect(EngineGlobals.GraphicsDevice);
            quadEffect.EnableDefaultLighting();
            quadEffect.World = Matrix.Identity;
            quadEffect.DiffuseColor = highlightColor.ToVector3();
            quadEffect.Alpha = 0.5f;

            CreateLines();

            this.bones = new Matrix[this.models[0].Bones.Count];
            this.models[0].CopyAbsoluteBoneTransformsTo(bones);

            Transforms = new GroupObject();

            GizmoMode = GizmoMode.Translate;

            this.gridSpacing = 100.0f;
        }

        private void CreateLines()
        {
            axisColors = new Color[3];
            axisColors[0] = Color.Red;
            axisColors[1] = Color.Green;
            axisColors[2] = Color.Blue;
            highlightColor = Color.Gold;

            // translucent quads
            #region Translucent Quads
            float doubleOffset = lineOffset * 2;
            quads = new Quad[3];
            quads[0] = new Quad(new Vector3(lineOffset, lineOffset, 0), Vector3.Backward, Vector3.Up, doubleOffset, doubleOffset); //XY
            quads[1] = new Quad(new Vector3(lineOffset, 0, lineOffset), Vector3.Up, Vector3.Right, doubleOffset, doubleOffset); //XZ
            quads[2] = new Quad(new Vector3(0, lineOffset, lineOffset), Vector3.Right, Vector3.Up, doubleOffset, doubleOffset); //ZY 
            #endregion

            // fill array with vertex-data
            #region Fill Axis-Line array
            List<VertexPositionColor> vertexList = new List<VertexPositionColor>(18);

            // helper to apply colors
            Color xColor = axisColors[0];
            Color yColor = axisColors[1];
            Color zColor = axisColors[2];

            float doubleLineOffset = lineOffset * 2;

            // -- X Axis -- // index 0 - 5
            vertexList.Add(new VertexPositionColor(new Vector3(lineOffset, 0, 0), xColor));
            vertexList.Add(new VertexPositionColor(new Vector3(lineLength, 0, 0), xColor));

            vertexList.Add(new VertexPositionColor(new Vector3(doubleLineOffset, 0, 0), xColor));
            vertexList.Add(new VertexPositionColor(new Vector3(doubleLineOffset, doubleLineOffset, 0), xColor));

            vertexList.Add(new VertexPositionColor(new Vector3(doubleLineOffset, 0, 0), xColor));
            vertexList.Add(new VertexPositionColor(new Vector3(doubleLineOffset, 0, doubleLineOffset), xColor));

            // -- Y Axis -- // index 6 - 11
            vertexList.Add(new VertexPositionColor(new Vector3(0, lineOffset, 0), yColor));
            vertexList.Add(new VertexPositionColor(new Vector3(0, lineLength, 0), yColor));

            vertexList.Add(new VertexPositionColor(new Vector3(0, doubleLineOffset, 0), yColor));
            vertexList.Add(new VertexPositionColor(new Vector3(doubleLineOffset, doubleLineOffset, 0), yColor));

            vertexList.Add(new VertexPositionColor(new Vector3(0, doubleLineOffset, 0), yColor));
            vertexList.Add(new VertexPositionColor(new Vector3(0, doubleLineOffset, doubleLineOffset), yColor));

            // -- Z Axis -- // index 12 - 17
            vertexList.Add(new VertexPositionColor(new Vector3(0, 0, lineOffset), zColor));
            vertexList.Add(new VertexPositionColor(new Vector3(0, 0, lineLength), zColor));

            vertexList.Add(new VertexPositionColor(new Vector3(0, 0, doubleLineOffset), zColor));
            vertexList.Add(new VertexPositionColor(new Vector3(doubleLineOffset, 0, doubleLineOffset), zColor));

            vertexList.Add(new VertexPositionColor(new Vector3(0, 0, doubleLineOffset), zColor));
            vertexList.Add(new VertexPositionColor(new Vector3(0, doubleLineOffset, doubleLineOffset), zColor));

            // -- Convert to array -- //
            translationLineVertices = vertexList.ToArray();
            #endregion
        }

        private void TransformsChanged(object sender, System.EventArgs e)
        {
            positionFloat = transforms.Position;

            initialPosition = transforms.Position;
            initialRotation = transforms.Rotation;

            visible = (transforms.Count > 0);
        }

        private void HandleInput()
        {
            Ray ray = EngineGlobals.GetMouseRay();
            currentAxis = Vector3.Zero;

            if (GizmoMode == GizmoMode.Rotate)
            {
                if (X_Box.Intersects(ref ray) != null || X_Sphere.Intersects(ray) != null)
                {
                    currentAxis = Vector3.UnitX;
                    gizmoAxis = GizmoAxis.X;
                }

                else if (Y_Box.Intersects(ref ray) != null || Y_Sphere.Intersects(ray) != null)
                {
                    currentAxis = Vector3.UnitY;
                    gizmoAxis = GizmoAxis.Y;
                }

                else if (Z_Box.Intersects(ref ray) != null || Z_Sphere.Intersects(ray) != null)
                {
                    currentAxis = Vector3.UnitZ;
                    gizmoAxis = GizmoAxis.Z;
                }
            }

            else
            {
                if (X_Box.Intersects(ref ray) != null || X_Sphere.Intersects(ray) != null)
                {
                    if (orientation == GizmoOrientation.Local || orientation == GizmoOrientation.Camera)
                    {
                        currentAxis = Vector3.Transform(Vector3.UnitX, Rotation);
                        gizmoAxis = GizmoAxis.X;
                    }
                    else
                    {
                        currentAxis = Vector3.UnitX;
                        gizmoAxis = GizmoAxis.X;
                    }
                }
                else if (Y_Box.Intersects(ref ray) != null || Y_Sphere.Intersects(ray) != null)
                {
                    if (orientation == GizmoOrientation.Local || orientation == GizmoOrientation.Camera)
                    {
                        currentAxis = Vector3.Transform(Vector3.UnitY, Rotation);
                        gizmoAxis = GizmoAxis.Y;
                    }
                    else
                    {
                        currentAxis = Vector3.UnitY;
                        gizmoAxis = GizmoAxis.Y;
                    }
                }
                else if (Z_Box.Intersects(ref ray) != null || Z_Sphere.Intersects(ray) != null)
                {
                    if (orientation == GizmoOrientation.Local || orientation == GizmoOrientation.Camera)
                    {
                        currentAxis = Vector3.Transform(Vector3.UnitZ, Rotation);
                        gizmoAxis = GizmoAxis.Z;
                    }
                    else
                    {
                        currentAxis = Vector3.UnitZ;
                        gizmoAxis = GizmoAxis.Z;
                    }
                }
            }

            manipulating = (currentAxis != Vector3.Zero);

            if (manipulating)
            {
                initialPosition = Transforms.Position;
                initialRotation = Transforms.Rotation;
            }
        }

        private void Translate()
        {
            ICamera camera = EngineGlobals.Camera;

            Matrix translation = Matrix.CreateTranslation(positionFloat);

            Vector3 start_position = EngineGlobals.GraphicsDevice.Viewport.Project(
                Vector3.Zero, camera.Projection, camera.View, translation);
            Vector3 end_position = EngineGlobals.GraphicsDevice.Viewport.Project(
                currentAxis, camera.Projection, camera.View, translation);

            Vector3 screen_direction = Vector3.Normalize(end_position - start_position);

            float amount = Vector3.Dot(screen_direction, new Vector3(mouseDifference, 0f));
            Vector3 difference = currentAxis * amount * (scale / 38);

            BoundingFrustum frustrum = new BoundingFrustum(camera.View * camera.Projection);

            if (frustrum.Contains(transforms.Position + difference) == ContainmentType.Contains)
            {
                if (currentAxis.Y == 0)
                    difference.Y = 0;

                if ((Keyboard.GetState().IsKeyDown(Keys.LeftControl) &&
                    Keyboard.GetState().GetPressedKeys().Length == 1) || snapToGrid)
                {
                    positionFloat += difference;

                    transforms.Position = new Vector3((int)positionFloat.X / (int)gridSpacing,
                        (int)positionFloat.Y / (int)gridSpacing, (int)positionFloat.Z / (int)gridSpacing);

                    transforms.Position *= gridSpacing;
                }

                else
                {
                    transforms.Position += (difference);
                    positionFloat = transforms.Position;
                }
            }
        }
        private void Rotate()
        {
            float deltaRadian = mouseDifference.X * EngineGlobals.DegreesToRadians;

            transforms.UpdateRotations(Quaternion.CreateFromAxisAngle(
                currentAxis, deltaRadian), orientation == GizmoOrientation.Local || orientation == GizmoOrientation.Camera);
        }
        private void Scale()
        {
            ICamera camera = EngineGlobals.Camera;

            Matrix translation = Matrix.CreateTranslation(positionFloat);

            Vector3 start_position = EngineGlobals.GraphicsDevice.Viewport.Project(
                Vector3.Zero, camera.Projection, camera.View, translation);
            Vector3 end_position = EngineGlobals.GraphicsDevice.Viewport.Project(
                currentAxis, camera.Projection, camera.View, translation);

            Vector3 screen_direction = Vector3.Normalize(end_position - start_position);

            float amount = Vector3.Dot(screen_direction, new Vector3(mouseDifference, 0f)) * (scale);

//            float amount = Vector3.Dot(screen_direction, mouseDirection);
            transforms.UpdateScale(amount / 1000);
        }

        public virtual void Update(bool dragging, ICamera camera)
        {
            visible = (transforms != null) && (transforms.Count > 0);

            scale = Vector3.Dot((position - camera.Position), camera.Forward) * 0.05f;

            if (visible && dragging == false)
            {
                mouseState = Mouse.GetState();

                mouseDifference = new Vector2(mouseState.X - 
                    prevMouseState.X, mouseState.Y - prevMouseState.Y);

                if (mouseState.LeftButton == ButtonState.Pressed &&
                    prevMouseState.LeftButton == ButtonState.Released && !manipulating)
                {
                    HandleInput();
                }

                else if (mouseState.LeftButton == ButtonState.Pressed &&
                    prevMouseState.LeftButton == ButtonState.Pressed)
                {
                    if (manipulating)
                    {
                        if (gizmoMode == GizmoMode.Translate)
                            Translate();
                        else if (gizmoMode == GizmoMode.Rotate)
                            Rotate();
                        else if (gizmoMode == GizmoMode.Scale)
                            Scale();
                    }
                }

                else if (mouseState.LeftButton == ButtonState.Released &&
                    prevMouseState.LeftButton == ButtonState.Pressed && manipulating)
                {
                    manipulating = false;

                    if (gizmoMode == GizmoMode.Rotate)
                        transforms.UpdateBounds();
                }

                prevMouseState = mouseState;
            }
        }

        private void DrawBoxes()
        {
            for (int i = 0; i < transforms.Count; i++)
            {
                BoundingBox box = EngineGlobals.Scene.GetBaseObject(transforms.Objects[i]).Bounds;
                ShapeRenderer.AddBoundingBox(box, Color.Red);
            }
        }

        public virtual void Draw()
        {
            if (transforms != null)
            {
                transforms.Update();
            }

            if (GizmoMode == GizmoMode.Rotate)
            {
                position = (transforms.RotatePerObject) ? transforms.Position : transforms.RotationOrigin;
            }
            else
            {
                position = transforms.Position;
            }

            if (visible)
            {
                ICamera camera = EngineGlobals.Camera;

                if (!manipulating)
                    DrawBoxes();

                scale = Vector3.Dot((position - camera.Position), camera.Forward) * 0.05f;

                EngineGlobals.GraphicsDevice.DepthStencilState = DepthStencilState.None;

                #region Draw: Axis-Lines
                // -- Draw Lines -- //
                lineEffect.World = World;
                lineEffect.View = camera.View;
                lineEffect.Projection = camera.Projection;

                lineEffect.CurrentTechnique.Passes[0].Apply();
                {
                    EngineGlobals.GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, 
                        translationLineVertices, 0, translationLineVertices.Length / 2);
                }

                #endregion

                if (gizmoMode == GizmoMode.Translate || gizmoMode == GizmoMode.Scale)
                {
                    #region Translate & NonUniformScale
                    // these two modes share a lot of the same draw-code

                    // -- Draw Quads -- //
                    //if (gizmoAxis == GizmoAxis.XY || gizmoAxis == GizmoAxis.YZ || gizmoAxis == GizmoAxis.ZX)
                    //{
                    //    EngineGlobals.GraphicsDevice.BlendState = BlendState.AlphaBlend;
                    //    EngineGlobals.GraphicsDevice.RasterizerState = RasterizerState.CullNone;

                    //    quadEffect.World = World;
                    //    quadEffect.View = camera.View;
                    //    quadEffect.Projection = camera.Projection;

                    //    quadEffect.CurrentTechnique.Passes[0].Apply();

                    //    Quad activeQuad = new Quad();
                    //    switch (gizmoAxis)
                    //    {
                    //        case GizmoAxis.XY:
                    //            activeQuad = quads[0];
                    //            break;
                    //        case GizmoAxis.ZX:
                    //            activeQuad = quads[1];
                    //            break;
                    //        case GizmoAxis.YZ:
                    //            activeQuad = quads[2];
                    //            break;
                    //    }

                    //    EngineGlobals.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,
                    //        activeQuad.Vertices, 0, 4,
                    //        activeQuad.Indexes, 0, 2);

                    //    EngineGlobals.GraphicsDevice.BlendState = BlendState.Opaque;
                    //    EngineGlobals.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
                    //}

                    if (gizmoMode == GizmoMode.Translate)
                    {
                        // -- Draw Cones -- //
                        for (int i = 0; i < 3; i++) // 3 = nr. of axis (order: x, y, z)
                        {
                            foreach (ModelMesh mesh in models[(int)gizmoMode].Meshes)
                            {
                                foreach (ModelMeshPart meshpart in mesh.MeshParts)
                                {
                                    BasicEffect effect = (BasicEffect)meshpart.Effect;
                                    Vector3 color = axisColors[i].ToVector3();

                                    effect.World = modelLocalSpace[i] * World;
                                    effect.DiffuseColor = color;
                                    effect.EmissiveColor = color;

                                    effect.EnableDefaultLighting();

                                    effect.View = camera.View;
                                    effect.Projection = camera.Projection;
                                }
                                mesh.Draw();
                            }
                        }
                    }
                    else
                    {
                        // -- Draw Boxes -- //
                        for (int i = 0; i < 3; i++) // 3 = nr. of axis (order: x, y, z)
                        {
                            foreach (ModelMesh mesh in models[(int)gizmoMode].Meshes)
                            {
                                foreach (ModelMeshPart meshpart in mesh.MeshParts)
                                {
                                    BasicEffect effect = (BasicEffect)meshpart.Effect;
                                    Vector3 color = axisColors[i].ToVector3();

                                    effect.World = modelLocalSpace[i] * World;
                                    effect.DiffuseColor = color;
                                    effect.EmissiveColor = color;

                                    effect.EnableDefaultLighting();

                                    effect.View = camera.View;
                                    effect.Projection = camera.Projection;
                                }
                                mesh.Draw();
                            }
                        }
                    }
                    #endregion
                }
                else if (gizmoMode == GizmoMode.Rotate)
                {
                    #region Rotate
                    // -- Draw Circle-Arrows -- //
                    for (int i = 0; i < 3; i++) // 3 = nr. of axis (order: x, y, z)
                    {
                        foreach (ModelMesh mesh in models[(int)gizmoMode].Meshes)
                        {
                            foreach (ModelMeshPart meshpart in mesh.MeshParts)
                            {
                                BasicEffect effect = (BasicEffect)meshpart.Effect;
                                Vector3 color = axisColors[i].ToVector3();

                                effect.World = modelLocalSpace[i] * World;
                                effect.DiffuseColor = color;
                                effect.EmissiveColor = color;

                                effect.EnableDefaultLighting();

                                effect.View = camera.View;
                                effect.Projection = camera.Projection;
                            }
                            mesh.Draw();
                        }
                    }
                    #endregion
                }

                EngineGlobals.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            }
        }
    }
}
